package com.macro.mall.portal.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.macro.mall.common.exception.ApiException;
import com.macro.mall.common.service.RedisService;
import com.macro.mall.portal.config.WeChatConfig;
import com.macro.mall.portal.domain.wechat.AccessTokenResult;
import com.macro.mall.portal.domain.wechat.UserPhoneInfo;
import com.macro.mall.portal.domain.wechat.WeChatResult;
import com.macro.mall.portal.service.WeChatService;
import com.macro.mall.portal.util.WeChatConstants;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author：郎
 * @name：WeChatServiceImpl
 * @date：2023/12/18 12:20
 */
@Service
@AllArgsConstructor
public class WeChatServiceImpl implements WeChatService {
    private static final Logger LOGGER = LoggerFactory.getLogger(WeChatServiceImpl.class);
    private final WeChatConfig weChatConfig;
    private final RedisService redisService;

    @Override
    public WeChatResult code2session(String code) {
        int retryTimes = 0;
        Map<String, String> wxParam = new HashMap<>(4);
        wxParam.put("appid", weChatConfig.getAppId());
        wxParam.put("secret", weChatConfig.getAppSecret());
        wxParam.put("js_code", code);
        wxParam.put("grant_type", "authorization_code");
        WeChatResult weChatResult = null;
        while (retryTimes < 3) {
            HttpResponse execute = HttpUtil.createGet(WeChatConstants.WECHAT_URL_CODE_2_SESSION).formStr(wxParam).execute();
            if (execute.isOk()) {
                weChatResult = JSONObject.parseObject(execute.body(), WeChatResult.class);
                LOGGER.debug("请求code2session的返回值：" + execute.body());
                //没有获取到sessionKey或者openid可能是由于参数问题或者网络抖动引起的，需要重试
                if (StrUtil.isBlank(weChatResult.getOpenid())) {
                    int errCode = weChatResult.getErrcode();
                    switch (errCode) {
                        case 40029:
                            throw new ApiException("code无效");
                        case 40226:
                            throw new ApiException("高风险等级用户，小程序登录拦截 ");
                        case 45011:
                            LOGGER.error("API 调用太频繁，请稍候再试");
                            break;
                        case -1:
                            LOGGER.error("系统繁忙，此时请开发者稍候再试");
                            break;
                        default:
                            break;
                    }
                } else {
                    return weChatResult;
                }
            }
            retryTimes++;
        }
        if (Objects.isNull(weChatResult)) {
            throw new ApiException("重试3次获取sessionKey依旧失败，请联系管理员！");
        }
        return weChatResult;
    }

    @Override
    public AccessTokenResult getAccessToken() {
        Map<String, String> wxParam = new HashMap<>(3);
        wxParam.put("appid", weChatConfig.getAppId());
        wxParam.put("secret", weChatConfig.getAppSecret());
        wxParam.put("grant_type", "client_credential");
        HttpResponse execute = HttpUtil.createGet(WeChatConstants.WECHAT_URL_GET_ACCESS_TOKEN).formStr(wxParam).execute();
        if (execute.isOk()) {
            AccessTokenResult accessTokenResult = JSONObject.parseObject(execute.body(), AccessTokenResult.class);
            redisService.set(WeChatConstants.REDIS_KEY_ACCESS_TOKEN, accessTokenResult.getAccessToken(), accessTokenResult.getExpiresIn());
            return accessTokenResult;
        } else {
            throw new ApiException("获取accessToken失败");
        }
    }

    @Override
    public UserPhoneInfo getUserPhoneNumber(String phoneCode) {
        Map<String, String> wxParam = new HashMap<>(1);
        Object accessKey = redisService.get(WeChatConstants.REDIS_KEY_ACCESS_TOKEN);
        String accessToken;
        if (Objects.isNull(accessKey)) {
            accessToken = getAccessToken().getAccessToken();
        } else {
            accessToken = accessKey.toString();
        }
        wxParam.put("code", phoneCode);
        HttpResponse execute = HttpUtil.createPost(WeChatConstants.WECHAT_URL_GET_USER_PHONE_NUMBER + "?access_token=" + accessToken)
                                       .body(JSONObject.toJSONString(wxParam)).execute();
        if (execute.isOk()) {
            return JSONObject.parseObject(execute.body(), UserPhoneInfo.class);
        } else {
            throw new ApiException("获取用户手机号信息失败");
        }
    }
}
